#include "oled.h"
#include "oledfont.h" 

#include <math.h>
#include <stdlib.h>
#include <string.h>  // For memcpy

#include <stdio.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_i2c.h"
#include "wifiiot_errno.h"


static uint32_t ssd1306_SendData(uint8_t* data, size_t size)
{
    WifiIotI2cIdx id = WIFI_IOT_I2C_IDX_0;
    WifiIotI2cData i2cData = {0};
    i2cData.sendBuf = data;
    i2cData.sendLen = size;

    return I2cWrite(id, OLED_I2C_ADDR, &i2cData);
}

static uint32_t ssd1306_WiteByte(uint8_t regAddr, uint8_t byte)
{
    uint8_t buffer[] = {regAddr, byte};
    return ssd1306_SendData(buffer, sizeof(buffer));
}

void Write_Byte_to_OLED(uint8_t data, uint8_t cmd_or_data)
{
    if(cmd_or_data == OLED_CMD)
    {
       ssd1306_WiteByte(OLED_CMD, data);
    }
    else if(cmd_or_data == OLED_DATA)
    {
       ssd1306_WiteByte(OLED_DATA, data);
    }
}


void oled_init(void)
{
    GpioInit();
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_13, WIFI_IOT_IO_FUNC_GPIO_13_I2C0_SDA);
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_IO_FUNC_GPIO_14_I2C0_SCL);
    I2cInit(WIFI_IOT_I2C_IDX_0, OLED_I2C_BAUDRATE);
  
    Write_Byte_to_OLED(0xAE,OLED_CMD);//--display off
	
	Write_Byte_to_OLED(0x00,OLED_CMD);//---set low column address
	Write_Byte_to_OLED(0x10,OLED_CMD);//---set high column address
	
	Write_Byte_to_OLED(0x40,OLED_CMD);//--set start line address  
	Write_Byte_to_OLED(0xB0,OLED_CMD);//--set page address
	Write_Byte_to_OLED(0x81,OLED_CMD); // contract control
	Write_Byte_to_OLED(0xFF,OLED_CMD);//--128   
	Write_Byte_to_OLED(0xA1,OLED_CMD);//set segment remap 
	Write_Byte_to_OLED(0xA6,OLED_CMD);//--normal / reverse
	Write_Byte_to_OLED(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	Write_Byte_to_OLED(0x3F,OLED_CMD);//--1/32 duty
	Write_Byte_to_OLED(0xC8,OLED_CMD);//Com scan direction
	Write_Byte_to_OLED(0xD3,OLED_CMD);//-set display offset
	Write_Byte_to_OLED(0x00,OLED_CMD);//
	
	Write_Byte_to_OLED(0xD5,OLED_CMD);//set osc division
	Write_Byte_to_OLED(0x80,OLED_CMD);//
	
	Write_Byte_to_OLED(0xD8,OLED_CMD);//set area color mode off
	Write_Byte_to_OLED(0x05,OLED_CMD);//
	
	Write_Byte_to_OLED(0xD9,OLED_CMD);//Set Pre-Charge Period
	Write_Byte_to_OLED(0xF1,OLED_CMD);//
	
	Write_Byte_to_OLED(0xDA,OLED_CMD);//set com pin configuartion
	Write_Byte_to_OLED(0x12,OLED_CMD);//
	
	Write_Byte_to_OLED(0xDB,OLED_CMD);//set Vcomh
	Write_Byte_to_OLED(0x30,OLED_CMD);//
	
	Write_Byte_to_OLED(0x8D,OLED_CMD);//set charge pump enable
	Write_Byte_to_OLED(0x14,OLED_CMD);//
	
	Write_Byte_to_OLED(0xAF,OLED_CMD);//--turn on OLED panel
}

void OLED_Display_Off(void)
{
	Write_Byte_to_OLED(0X8D,OLED_CMD);  						//SET DCDC命令
	Write_Byte_to_OLED(0X10,OLED_CMD);  						//DCDC OFF
	Write_Byte_to_OLED(0XAE,OLED_CMD);  						//DISPLAY OFF
}
void OLED_Display_On(void)
{
	Write_Byte_to_OLED(0X8D,OLED_CMD);  						//SET DCDC命令
	Write_Byte_to_OLED(0X14,OLED_CMD);  						//DCDC ON
	Write_Byte_to_OLED(0XAF,OLED_CMD);  						//DISPLAY ON
}

void OLED_Clear_Line(uint8_t line)  
{  
	uint8_t n;		    
	Write_Byte_to_OLED (0xb0+line,OLED_CMD);            //设置页地址（0~7）
	Write_Byte_to_OLED (0x00,OLED_CMD);                 //设置显示位置—列低地址
	Write_Byte_to_OLED (0x10,OLED_CMD);                 //设置显示位置—列高地址   
	for(n=0;n<128;n++)Write_Byte_to_OLED(0,OLED_DATA); 
}

void OLED_Clear_Line_x0_x1(uint8_t line0, uint8_t line1, uint8_t x0,  uint8_t x1)  
{  
	uint8_t i, j;
	if(line0 >= line1)
	{
		Write_Byte_to_OLED (0xb0+line0,OLED_CMD);            //设置页地址（0~7）
		Write_Byte_to_OLED (0x00,OLED_CMD);                 //设置显示位置—列低地址
		Write_Byte_to_OLED (0x10,OLED_CMD);                 //设置显示位置—列高地址   
		for(j=x0; j<x1; j++)Write_Byte_to_OLED(0,OLED_DATA);
	}
	else
	{
		for(i=line0; i<line1; i++)
		{
			Write_Byte_to_OLED (0xb0+i,OLED_CMD);            //设置页地址（0~7）
			Write_Byte_to_OLED (0x00,OLED_CMD);                 //设置显示位置—列低地址
			Write_Byte_to_OLED (0x10,OLED_CMD);                 //设置显示位置—列高地址   
			for(j=x0; j<x1; j++)Write_Byte_to_OLED(0,OLED_DATA); 
		}
	}
}

void OLED_Clear_All(void)  
{  
	uint8_t i,n;		    
	for(i=0;i<8;i++)  
	{  
		Write_Byte_to_OLED (0xb0+i,OLED_CMD);    //设置页地址（0~7）
		Write_Byte_to_OLED (0x00,OLED_CMD);      //设置显示位置—列低地址
		Write_Byte_to_OLED (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)Write_Byte_to_OLED(0,OLED_DATA); 
	} //更新显示
}

void OLED_Test_All(void)  
{  
	uint8_t i,n;		    
	for(i=0;i<8;i++)  
	{  
		Write_Byte_to_OLED (0xb0+i,OLED_CMD);    //设置页地址（0~7）
		Write_Byte_to_OLED (0x00,OLED_CMD);      //设置显示位置—列低地址
		Write_Byte_to_OLED (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)Write_Byte_to_OLED(0xff,OLED_DATA); 
	} //更新显示
}

//在指定位置显示一个字符,包括部分字符
//size：字符大小，大的8*16，小的就6*8
void OLED_Show_Char(uint8_t x, uint8_t y, uint8_t size, uint8_t character)
{
	unsigned char c=0,i=0;	
	c=character-' ';//得到偏移后的值			
	if(x>Max_Column-1){x=0;y=y+2;}
	if(size == 16)
	{
		OLED_Set_Pos(x,y);	
		for(i=0;i<8;i++)
		Write_Byte_to_OLED(F8X16[c*16+i],OLED_DATA);
		OLED_Set_Pos(x,y+1);
		for(i=0;i<8;i++)
		Write_Byte_to_OLED(F8X16[c*16+i+8],OLED_DATA);
	}
	else if(size == 8)
	{
		OLED_Set_Pos(x,y+1);
		for(i=0;i<6;i++)
		Write_Byte_to_OLED(F6x8[c][i],OLED_DATA);
	}
}
//在指定位置显示一个字符号串
//size：字符大小，大的8*16（输入16），小的就6*8（输入任意）,
void OLED_Show_String(uint8_t x, uint8_t y, uint8_t size, uint8_t *chr)
{
	unsigned char j=0;
	while (chr[j]!='\0')
	{		OLED_Show_Char(x,y,size,chr[j]);
			x+=8;
		if(x>120){x=0;y+=2;}
			j++;
	}
}
//显示汉字
void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no)
{      			    
	uint8_t t,adder=0;
	OLED_Set_Pos(x,y);	
    for(t=0;t<16;t++)
    {
        Write_Byte_to_OLED(Common_Chinese_Characters[2*no][t],OLED_DATA);
        adder+=1;
    }
    OLED_Set_Pos(x,y+1);	
    for(t=0;t<16;t++)
    {	
        Write_Byte_to_OLED(Common_Chinese_Characters[2*no+1][t],OLED_DATA);
        adder+=1;
    }					
}


void OLED_Set_Pos(uint8_t x, uint8_t y) 
{ 
	Write_Byte_to_OLED(0xb0+y,OLED_CMD);
	Write_Byte_to_OLED(((x&0xf0)>>4)|0x10,OLED_CMD);
	Write_Byte_to_OLED((x&0x0f)|0x01,OLED_CMD); 
}

static uint32_t oled_pow(uint8_t m, uint8_t n)
{
	uint32_t result = 1;	 
	while(n--)
	{
		result *= m;    
	}
	return result;
}

void OLED_Show_Num(uint8_t x,uint8_t y,uint32_t num,uint8_t len)
{         	
	uint8_t t,temp;
	uint8_t enshow=0;				
	
	for(t=0; t<len; t++){ 
		temp=(num/oled_pow(10, len-t-1))%10;//把多位数的数值分出来  从高到低
		
		if(enshow == 0 && t < (len-1))  //排除最后一位数  第一位
		{
			if(temp == 0)
			{
				OLED_Show_Char( x+(SIZEGAP/2)*t, y, 16, '0');//最高位为0则显示为空
				continue;
			}
			else
			{
				enshow=1; 
			}		 	 
		}
	 	OLED_Show_Char( x+(SIZEGAP/2)*t, y, 16, temp+'0'); 
	}
} 